<?php
//命名空间
namespace core;
//引入全局空间类:PDO三类
use \PDO, \PDOStatement, \PDOException;

echo '<pre>';

/**
 * Class Dao
 * @package core
 */
class Dao
{
    /**
     * @var object $pdo PDO对象
     * @var object $fetch_mode 取出数据的模式
     */
    private $pdo;
    private $fetch_mode;

    /**
     * Dao constructor.
     * @param array $info
     * @param array $drivers
     */
    public function __construct(array $info = [], array $drivers = [])
    {
        $type = $info['type'] ?? 'mysql';
        $host = $info['host'] ?? 'localhost';
        $port = $info['port'] ?? '3306';
        $username = $info['username'] ?? 'root';
        $password = $info['password'] ?? 'root';
        $dbname = $info['dbname'] ?? 'test';
        $charset = $info['charset'] ?? 'utf8';
        $this->fetch_mode = $info['fetch_mode'] ?? PDO::FETCH_ASSOC;

        //驱动控制:异常模式处理
        $drivers[PDO::ATTR_ERRMODE] = $drivers[PDO::ATTR_ERRMODE] ?? PDO::ERRMODE_EXCEPTION;
        //实例化PDO对象
        try {
            //增加错误抑制符防止意外 @
            $this->pdo = @new PDO($type . ':host=' . $host . ';port=' . $port . ';dbname=' . $dbname, $username, $password, $drivers);
        } catch (PDOException $e) {
            echo '数据库连接出现错误 <br>';
            echo '错误文件为:' . $e->getFile() . '<br>';
            echo '错误行号为:' . $e->getLine() . '<br>';
            echo '错误描述为:' . $e->getMessage() . '<br>';
            die();
        }
        //设定字符集
        try {
            $this->pdo->exec('set names ' . $charset);
        } catch (PDOException $e) {
            //调用异常处理方法
            $this->dao_exception($e);
        }
    }

    /**
     * 写操作
     * @param string $sql 写操作的sql语句
     */
    public function dao_exec(string $sql)
    {
        try {
            //调用执行:成功返回,错误捕捉
            $this->pdo->exec($sql);
        } catch (PDOException $exception) {
            $this->dao_exception($exception);
        }
    }

    /**
     * 写操作成功返回的自增长id
     * @return string 返回自增长id
     */
    public function dao_insert_id(): string
    {
        return $this->pdo->lastInsertId();
    }

    /**
     * 读方法:二合一,一条或多条
     * @param string $sql 查询的sql语句
     * @param bool $only 是否查询一条或者多条记录,默认查询一条
     * @return array   返回查询记录
     */
    public function dao_query(string $sql, bool $only = true): array
    {
        try {
            $stmt = $this->pdo->query($sql);
            //设置默认获取模式
            $stmt->setFetchMode($this->fetch_mode);
            //数据解析
            if ($only) {
                $row = $stmt->fetch();
                if (!$row) throw new PDOException('没有查询到该条记录');
                return $row;
            } else {
                $rows = $stmt->fetchAll();
                if (!$rows) throw new PDOException('没有查询到该条记录');
                return $rows;
            }
        } catch (PDOException $exception) {
            $this->dao_exception($exception);
        }
    }

    /**
     * SQL执行错误的异常处理
     * @param object $e PDOException的类对象
     */
    private function dao_exception(object $e)
    {
        echo 'SQL语句执行出现错误 <br>';
        echo '错误文件为:' . $e->getFile() . '<br>';
        echo '错误行号为:' . $e->getLine() . '<br>';
        echo '错误描述为:' . $e->getMessage() . '<br>';
        die();
    }
}

//测试
$dao = new Dao();
$sql = "select * from t_student where id=100";
$res = $dao->dao_query($sql);
print_r($res);
